package com.hmdp.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hmdp.constant.GlobalConstant;
import com.hmdp.entity.dto.Result;
import com.hmdp.entity.dto.UserDTO;
import com.hmdp.entity.Blog;
import com.hmdp.entity.User;
import com.hmdp.entity.vo.ScrollVO;
import com.hmdp.mapper.BlogMapper;
import com.hmdp.service.IBlogService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.service.IFollowService;
import com.hmdp.service.IUserService;
import com.hmdp.utils.SystemConstants;
import com.hmdp.utils.UserHolder;
import jodd.util.StringUtil;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
//import org.springframework.data.redis.core.redisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 虎哥
 * @since 2021-12-22
 */
@Service
public class BlogServiceImpl extends ServiceImpl<BlogMapper, Blog> implements IBlogService {
    @Autowired
    IUserService userService;
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    RedissonClient redissonClient;
    @Resource
    IFollowService followService;
//    @Autowired
//    StringRedisTemplate redisTemplate;
    @Override
    public Result getBlogById(Long id) {
        Blog blog = getById(id);
        queryBlogUser(blog);
        return Result.ok(blog);
    }

    private void queryBlogUser(Blog blog) {
        Long userId= blog.getUserId();
        User user = userService.getById(userId);
        Double score = redisTemplate.opsForZSet().score(GlobalConstant.BLOG_LIKE_ZSET_PREFIX + blog.getId(), UserHolder.getUser().getId().toString());
        blog.setIsLike(score!=null);
//        Boolean b = redisTemplate.opsForSet().isMember(GlobalConstant.BLOG_LIKE_SET_PREFIX + blog.getId(), UserHolder.getUser().getId().toString());
//        System.out.println(">>>>>>>>>>>>>"+b);
//        blog.setIsLike(BooleanUtil.isTrue(b));
        blog.setName(user.getNickName());
        blog.setIcon(user.getIcon());
    }
    @Transactional
    @Override
    public Result saveBlog(Blog blog) {
        // 获取登录用户
        UserDTO user = UserHolder.getUser();
        blog.setUserId(user.getId());
        // 保存探店博文
        this.save(blog);
//        redisTemplate.opsForSet().add(GlobalConstant.BLOG_LIKE_SET_PREFIX+blog.getId(),GlobalConstant.NULL_STRING);
        followService.query().eq("follow_user_id",user.getId()).list().stream().forEach(item->{
            redisTemplate.opsForZSet().add(GlobalConstant.INBOX_PREFIX+item.getUserId(),blog.getId().toString(),System.currentTimeMillis());
        });

        // 返回id
        return Result.ok(blog.getId());
    }
    @Override
    @Transactional
    public Result likeBlog(Long id) {
        Long userId = UserHolder.getUser().getId();
//        RLock lock = redissonClient.getLock(GlobalConstant.LOCK_BLOG_LIKE + userId);
//        if(!lock.tryLock())
//            return Result.fail(GlobalConstant.TRY_AGAIN_LATER);
//        Boolean b = redisTemplate.opsForSet().isMember(GlobalConstant.BLOG_LIKE_SET_PREFIX + id, userId.toString());
//        if(BooleanUtil.isTrue(b))
//        {
//            this.update()
//                    .setSql("liked = liked - 1").eq("id", id).update();
//            redisTemplate.opsForSet().remove(GlobalConstant.BLOG_LIKE_SET_PREFIX + id, userId.toString());
//
//        }
//        else{
//            // 修改点赞数量
//            this.update()
//                    .setSql("liked = liked + 1").eq("id", id).update();
//            redisTemplate.opsForSet().add(GlobalConstant.BLOG_LIKE_SET_PREFIX + id, userId.toString());
//
//        }
        Double score = redisTemplate.opsForZSet().score(GlobalConstant.BLOG_LIKE_ZSET_PREFIX + id, userId.toString());
        if(score!=null)
        {
            redisTemplate.opsForZSet().remove(GlobalConstant.BLOG_LIKE_ZSET_PREFIX + id, userId.toString());
            this.update()
                    .setSql("liked = liked - 1").eq("id", id).update();

        }
        else{
            // 修改点赞数量
            redisTemplate.opsForZSet().add(GlobalConstant.BLOG_LIKE_ZSET_PREFIX + id, userId.toString(),System.currentTimeMillis());
            this.update()
                    .setSql("liked = liked + 1").eq("id", id).update();
        }
        Blog blog = this.getById(id);
        System.out.println(">>>>>>>>>>>>>>>>>>:"+blog.getLiked());
//        lock.unlock();
        return Result.ok();
    }

    @Override
    public Result queryMyBlog(Integer current) {
        // 获取登录用户
        UserDTO user = UserHolder.getUser();
        // 根据用户查询
        Page<Blog> page = this.query()
                .eq("user_id", user.getId()).page(new Page<>(current, SystemConstants.MAX_PAGE_SIZE));
        // 获取当前页数据
        List<Blog> records = page.getRecords();
        return Result.ok(records);
    }

    @Override
    public Result queryHotBlog(Integer current) {
        // 根据用户查询
        Page<Blog> page = this.query()
                .orderByDesc("liked")
                .page(new Page<>(current, SystemConstants.MAX_PAGE_SIZE));
        // 获取当前页数据
        List<Blog> records = page.getRecords();
        // 查询用户
        records.forEach(this::queryBlogUser);
        return Result.ok(records);
    }

    @Override
    public Result likes(Long id) {
        Set<String> range = redisTemplate.opsForZSet().range(GlobalConstant.BLOG_LIKE_ZSET_PREFIX + id, 0, 4);
        if(range==null||range.isEmpty())
        {
            return Result.ok(Collections.emptyList());
        }
        List<Long> ids = range.stream().map(Long::valueOf).collect(Collectors.toList());
        String idsString = StringUtil.join(ids, ",");
        List<UserDTO> collect = userService.query().in("id", ids).last("order by field(id,"+idsString+")").list().stream().map(item -> {
            return BeanUtil.copyProperties(item, UserDTO.class);
        }).collect(Collectors.toList());
        return Result.ok(collect);
    }

    @Override
    public Result ofFollow(Long maxTime, Integer offset) {
        UserDTO user = UserHolder.getUser();
//        Set<String> strings = redisTemplate.opsForZSet().reverseRangeByScore(GlobalConstant.INBOX_PREFIX + user.getId(), 0, maxTime, offset, GlobalConstant.INBOX_REFRESH_NUM);
        Set<ZSetOperations.TypedTuple<String>> set = redisTemplate.opsForZSet()
                .reverseRangeByScoreWithScores(GlobalConstant.INBOX_PREFIX + user.getId(), 0, maxTime, offset, GlobalConstant.INBOX_REFRESH_NUM);
        if(set==null||set.isEmpty())
            return Result.ok();
        List<Long> list=new ArrayList<>(set.size());
        ScrollVO scrollVO = new ScrollVO();
        scrollVO.setMinTime(maxTime);
        scrollVO.setOffset(1);
        for (ZSetOperations.TypedTuple<String> stringTypedTuple : set) {
            list.add(Long.valueOf(stringTypedTuple.getValue()));
            if(stringTypedTuple.getScore()<scrollVO.getMinTime())
            {
                scrollVO.setMinTime(stringTypedTuple.getScore().longValue());
                scrollVO.setOffset(1);
            }
            else{
                scrollVO.setOffset(scrollVO.getOffset()+1);
            }
        }
        String idsString = StringUtil.join(list.stream().map(Object::toString).collect(Collectors.toList()),",");
        List<Blog> blogs=this.query().in("id",list).last("order by field(id,"+idsString+")").list();
        blogs.stream().forEach(this::queryBlogUser);
        scrollVO.setList(blogs);
        return Result.ok(scrollVO);
    }
}
